[X-Ray] X-Rayを使用して実行時間が長いLambda関数の資料を作成する
1 はじめに
AIソリューション部の平内(SIN)です。
Amazon Connectや、Amazon Alexaでは、Lambda関数を利用できますが、どちらもタイムアウトに制限(8秒)があり、時間内に処理できない場合、サービス側でエラーとなってしまいます。
このタイムアウトは絶対に避けることができないため、もし、処理時間が長くなる(若しくは、その危険性がある)場合、それを考慮した設計が必要になります。
下記は、実行時間が長い処理をSQSで処理するようにした例です。
Amazon ConnectとTwilioの連携
今回は、このような場合に、「何の処理に、どれ位時間がかかるので、このように設計しました」と明確に言うための資料としてX-Rayを簡単に使ってみたのでその記録です。
注:すいません。本記事は、X-Rayの特別な使い方を紹介するようなものではありません。利用手順をまとめただけの個人的な覚書です。
2 手順
今回作業した手順は、以下のとおりです。
- トレースの有効化
- aws-xray-sdk-coreの利用
- サブセグメントの生成(X-Ray対応外のファンクションを使用するため)
(1) トレースの有効化
Lambda関数からX-Rayを使用するには、デバッグとエラー処理のところで、アクティブトレースを有効にしますにチェックします。
(2) aws-xray-sdk-coreの利用
AWSのサービスをトレースするだけなら、aws-xray-sdk-coreでaws-sdkをラップするだけです。
const AWSXRay = require('aws-xray-sdk-core'); var AWS = AWSXRay.captureAWS(require('aws-sdk'));
(3) サブセグメントの生成
AWSのサービス以外をトレースしたい場合は、サブセグメントを生成して囲みます。
const seg = AWSXRay.getSegment(); const subsegment = AWSXRay.getSegment().addNewSubsegment('Twillo'); // ここに計測したいファンクションを記述する subsegment.close();
3 対象コード
サンプルで準備したコードは、以下のようなものです。
Connectから呼び出されるLambda関数をイメージしています。
- 電話番号をDynamoDBに記録する
- メッセージ文の雛形をS3から取得する
- SMSを送信する(Twilio)
const AWSXRay = require('aws-xray-sdk-core'); var AWS = AWSXRay.captureAWS(require('aws-sdk')); exports.handler = async (event) => { const phoneNumber = event.phoneNumber; // DynamoDBに電話番号を記録する const tableName = 'x-ray-sample'; const promaryKey = phoneNumber; const value = (new Date()).toString(); await dynamoDbPut(tableName, promaryKey, value); // S3からSMSの本文取得する const bucket = 'x-ray-sample'; const key = 'sms-message.txt'; const data = await s3GetObject(bucket, key); const body = data.Body.toString("utf-8"); // TwilioでSMS送信する const seg = AWSXRay.getSegment(); const subsegment = AWSXRay.getSegment().addNewSubsegment('Twillo'); const result = await createSMS(phoneNumber, body); console.log(result); subsegment.close(); }; async function s3GetObject(bucket, key) { var s3 = new AWS.S3(); var params = { Bucket: bucket, Key: key }; return await s3.getObject(params).promise(); } async function dynamoDbPut(tableName, promaryKey, value) { const client = new AWS.DynamoDB.DocumentClient(); let item = { "id": promaryKey, "value": value } var param = { TableName : tableName, Item: item }; return await client.put(param).promise(); } async function createSMS(to_number, body) { const account_sid = process.env.Sid; const auth_token = process.env.Token; const from_number = process.env.FromNumber; const client = require('twilio')( account_sid, auth_token ); return new Promise( (resolve, reject) => { client.messages.create({ from: from_number, to: to_number, body: body }) .then(response => { console.log(response); resolve(response.id); }) .catch( error => { reject(error); }) }) }
4 トレースの確認
X-RayのコンソールからTraceを選択し、適当な時間(過去、何分前までのものを検索対象とするか)を指定して更新すると、Traceリストに1回の実行が1行となって表示されます。
トレースを選択すると、その内容が確認できます。
TwilioのSMS送信処理で、12.3sかかっていることが分かります。この結果から、Twilioのレスポンスによって「送信しました/送信に失敗しました」のようなアナウンスを返す実装は不可能であることが分かります。
5 AWS_XRAY_CONTEXT_MISSING
実際の計測は、Lambdaの実行環境で行なうため、問題とならないのですが、デバッグ等のため、コードをローカルで実行しようとすると、下記のエラーが出ます。
Error: Failed to get the current sub/segment from the context.
このエラーは、AWS_XRAY_CONTEXT_MISSINGという環境変数が設定されていない事が原因のようです。
実環境で動作させると、LOG_ERRORという環境変数がセットされていることが確認できます。
console.log('AWS_XRAY_CONTEXT_MISSING=' + process.env.AWS_XRAY_CONTEXT_MISSING);
AWS_XRAY_CONTEXT_MISSING=LOG_ERROR
実際にローカルの実行環境で環境変数を設定するか、若しくは、下記のコードでこの問題を回避できます。
AWSXRay.setContextMissingStrategy('LOG_ERROR');
7 最後に
今回は、時間制限のある要件で、時間を要する処理があった場合に、その状況を把握して表現する方法としてX-Rayを使用してみました。
軽易に、使えるようにして、資料作成等に利用できるようしたいと思います。
8 参考リンク
ローカルで X-Ray デーモンを実行する
AWS X-Rayによるアプリケーションの分析とデバッグ
AWS Black Belt Online Seminar 「 AWS X-Ray」 資料及びQ&A公開
AWS X-Ray を使用する
AWS Lambda および AWS X-Ray